package jhavelogger.visitor;

import static org.junit.Assert.*;

import java.util.Date;

import jhavelogger.data.FakeIPLookup;
import jhavelogger.data.LogDAO;
import jhavelogger.models.AcceptedConnection;
import jhavelogger.models.SendAlgorithmToClient;
import jhavelogger.models.UsernameLookup;
import jhavelogger.models.DBLog;
import jhavelogger.models.UidOperation;
import junit.framework.Assert;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import static org.mockito.Mockito.*;

public class DBLogVisitorTests {

    private DBLogVisitor visitor;
    private LogDAO dao;
    
    /**
     * Constructs a fake LogDAO object for unit testing purposes. No actual
     * database will be interacted with. Also initializes a new DBLogVisitor
     * for testing purposes.
     * @throws Exception if an error occurred during setup
     */
    @Before
    public void setUp() throws Exception {
	this.dao = mock(LogDAO.class);
	this.visitor = new DBLogVisitor(this.dao, new FakeIPLookup());
    }

    @After
    public void tearDown() throws Exception {
    }

    @Test
    public void testVisitAcceptedConnectionAddsToDictionary() {
	// Ensure no db calls were made
	verifyNoMoreInteractions(dao);
	
	AcceptedConnection log = new AcceptedConnection("127.0.0.1", 113, "141.216.444.111");
	log.accept(this.visitor);

	String ip = this.visitor.getAcceptedConnections("127.0.0.1").get(113);
	Assert.assertNotNull("An IP address must be set in the accepted connections dictionary", ip);
	Assert.assertEquals("141.216.444.111", ip);
    }

    @Test
    public void testVisitAlgorithmLookup() throws Exception {
	// Ensure no db calls were made
	verifyNoMoreInteractions(dao);
	
	AcceptedConnection acceptedConnectionLog = new AcceptedConnection("127.0.0.1", 113, "141.216.444.111");
	acceptedConnectionLog.accept(this.visitor);
	
	UidOperation uidLog = new UidOperation("127.0.0.1", 113);
	uidLog.accept(this.visitor);
	
	UsernameLookup lookup = new UsernameLookup("127.0.0.1", "naps@uwosh.edu");
	lookup.accept(this.visitor);
	
	String username = this.visitor.getLastUsernameBySource("127.0.0.1");
	Assert.assertEquals("naps@uwosh.edu", username);
    }

    @Test
    public void testVisitSendAlgorithmToClient() throws Exception {
	AcceptedConnection acceptedConnectionLog = new AcceptedConnection("127.0.0.1", 113, "141.216.444.111");
	acceptedConnectionLog.accept(this.visitor);
	
	UidOperation uidLog = new UidOperation("127.0.0.1", 113);
	uidLog.accept(this.visitor);
	
	UsernameLookup lookup = new UsernameLookup("127.0.0.1", "naps@uwosh.edu");
	lookup.accept(this.visitor);
	
	SendAlgorithmToClient send = new SendAlgorithmToClient("127.0.0.1", new Date(2008, 10, 4), "sutherland/shc_exercise_2");
	DBLog log = (DBLog)send.accept(this.visitor);
	Assert.assertNotNull("A non-null object should be returned from the visitor", log);
	
	// Ensure a log was sent to the database and commit was called
	verify(this.dao).insertLog((DBLog)notNull());
	verify(this.dao).commit();
    }
    
    @Test
    public void testVisitUidOperationSetsLastUID() {
	// Ensure no db calls were made
	verifyNoMoreInteractions(dao);
	
	UidOperation log = new UidOperation("127.0.0.1", 19);
	log.accept(this.visitor);
	Assert.assertEquals(19, this.visitor.getLastUidOperation("127.0.0.1"));
    }

    @Test
    public void testVisitUidOperationOverwritesPreviousValue() {
	UidOperation log = new UidOperation("127.0.0.1", 19);
	log.accept(this.visitor);
	
	log = new UidOperation("127.0.0.1", 22);
	log.accept(this.visitor);
	Assert.assertEquals(22, this.visitor.getLastUidOperation("127.0.0.1"));
    }
    
    @Test
    public void testNoUidIsInitiallySet() {
	Assert.assertEquals(-1, this.visitor.getLastUidOperation("127.0.0.1"));
    }
}
